home *** CD-ROM | disk | FTP | other *** search
/ CD ROM Paradise Collection 4 / CD ROM Paradise Collection 4 1995 Nov.iso / edit / aaem95ma.zip / KEYF.CC < prev    next >
C/C++ Source or Header  |  1995-03-05  |  48KB  |  992 lines

  1. /* This file is KEYF.CC */
  2. #include "em.h"
  3. extern char*offscreen;
  4. int compare(line*X,line*Y);
  5. /*-----*/
  6. int caseq(val a,val b){reg int i;if(a.n<0?:b.n<0?:a.n!=b.n?:!a.s?:!b.s)return 0;
  7. for(i=a.n-1;i>=0;i--)if(to_upper(a.s[i])!=to_upper(b.s[i])) return 0; return 1;}
  8. /*-----*/
  9. char Filename[strsize]={0}; val Fn(Filename,0);
  10. /*-----*/
  11. int fileexists(char*s){int F=open(s,1);
  12. if(F>=0) {close(F); return 1;} else return 0;}
  13. /*-----*/
  14. char*keyname(int c,int alt/*=0*/){
  15. int i; val s; static char cc[2]=" ",ct[6]="ctrl ";
  16. if(alt) return altnames[c&255]?:"(unidentified code)";
  17. for(i=0;s=keynames[i],s.s;i++) if(c==s.n) return s.s;
  18. if(c<32) {ct[4]=c+64; return ct;} cc[0]=c; return cc;}
  19. /*-----*/
  20. int yesno(char*pt){char*yn[]={"Yes","No"}; return 1-bottommenu(pt,1,"YN",yn,4);}
  21. //int yesno(char*pt){char *s; int c,i,j=0,k,n=0,yn,ptl=strlen(pt);
  22. //static char *YN="(Y or N)"; int L=gp_Rows-1; uns short*S=Sl[L].sa,T[256];
  23. //k=strlen(YN)<?(gp_Cols-ptl);
  24. //A: gp_clear(L); for(i=ptl+k-1;i>=0;i--) T[i]=S[i]; /* save overwritten text */
  25. //for(i=0;i<ptl;i++) S[i]=sch(pt[i],Magenta);
  26. //if(j) for(i=k-1;i>=0;i--) S[i+ptl]=sch(YN[i],Red);
  27. //cursor.r=L; cursor.c=(n+ptl)<?(gp_Cols-1); gp_cursor(cursor);
  28. //c=getkey(); if(c>0) c=to_upper(c);
  29. //if(c=='Y') {yn=1; goto OUT;} if(c=='N') {yn=0; goto OUT;}
  30. //else if(c==-alt_end) MOAN("user abort"); j++; goto A;
  31. //OUT: Sl[L].ok=0;  for(i=ptl+k-1;i>=0;i--) S[i]=T[i]; return yn;}
  32. /*----- bind key to needing another key typed after it */
  33. void keyarray::subarray(){a=0; n=0;}
  34. void val::subarray(){k=new keyarray; k->subarray(); n=_keyarray;}
  35. /*-----*/
  36. val key0; keyarray keys; /* head of lookup tree of key bindings */
  37. /*----- keyarray[int] : look up key */
  38. val&keyarray::operator[](int N){int i,j; val *Q; if(N<n) return a[N];
  39. j=(N+8)&~7; Q=new val[j]; /* if out of bounds, lengthen array */
  40. for(i=n-1;i>=0;i--) Q[i]=a[i]; for(i=n;i<j;i++) Q[i]=val();
  41. n=j; delete a; a=Q; return a[N]; }
  42. /*----- val[int]: ditto */
  43. val&val::operator[](int N){
  44. if(n!=_keyarray) MOAN("BUG: this is not a keyarray"); return (*k)[N];}
  45. /*----- obey a macstep bound to a char */
  46. void Insert(int N,byte c){int i; for(i=0;i<N;i++) *B+=c;}
  47. /*----- list key binding info in current buffer */
  48. void keyarray::print(int N/*=1*/,int i/*=1*/,int deep/*=1*/){
  49. val*k; int I,j,alt=i?0:1;
  50. for(I=0;I<n;I++) {k=&a[I]; keyseqc[deep]=I; keyseqc[0]=deep+1;
  51.     if(N) {if(!i) if(!altnames[I]) if(!k->n) if(!k->k) continue;
  52.     if(deep>alt) if(!k->k) continue;
  53.     for(j=0;j<deep;j++) *B+=(char)9; /* tab */
  54.     pb("%3d = '%s': %3d %8x ",I,keyname(I,alt),k->n,k->k);}
  55.     else {if(!N) if(!k->k) continue; pb("%k :: ",&keyseq);}
  56.     macstep(*k,1,0).print(); ::newline();
  57.     if(k->n==_char) k->m->print();
  58.     else if(k->n==_keyarray) k->k->print(N,I,deep+1);}}
  59. /*-----*/
  60. void keyarray::search(void(*fn)(val&ka)){val*k; int I,j;
  61. for(I=0;I<n;I++) if(k=&a[I], k->n==_keyarray) k->k->search(fn); else (*fn)(*k);}
  62. /*-----*/
  63. KF(newline) {reg int i; for(i=0;i<N.i;i++) B->dot/1;}
  64. /*-----*/
  65. KF(linefeed) {reg int i; for(i=0;i<N.i;i++) {B->dot/1; B->dot.r->no_cr(1);}}
  66. /*-----*/
  67. KF(copykill) {(B->Mark(N.i)-B->dot).copykill();}
  68. /*-----*/
  69. KF(page_down) {int i,j=(B->nrows-3)>?1,k=j*N.i; B->dotcc=B->dotcc2;
  70. /* if(!play) if(cursor.r!=255) k+=(B->row1+B->nrows/2-cursor.r); */
  71. if(B->longlines) {B->dispfold(k); return;}
  72. if(N.i>0) for(i=N.i*j;i>0;i--) {if(!(B->start.Down())) break;}
  73. else      for(i=N.i*j;i<0;i++) {if(!(B->start.Up  ())) break;}
  74. if(i>0) {B->dot=B->eof(); MOAN("hit end of buffer");}
  75. if(i<0) {B->dot=B->bof(); MOAN("hit start of buffer");}
  76. B->dot=B->start; for(i=B->nrows/2;i>0;i--) B->down();}
  77. /*-----*/
  78. KF(page_up) {page_down(-N);}
  79. /*-----*/
  80. KF(gotobof) {B->dot.r=B->text.next; B->dot.c=0; B->dotcc=B->dotcc2=-1;}
  81. /*-----*/
  82. KF(gotoeof) {line*L=B->dot.r=B->text.prev; B->dot.c=L->n;}
  83. /*----- remove final CR char and clear 'no CR' bit, if both found */
  84. void crcheck(line*L){if(L->no_cr()) if(L->n) if(L->s[L->n-1]==CR) {
  85.     *L=L->n-1; L->no_cr(0); /* L->la(1); B->changed=1; */ }}
  86. /*-----*/
  87. KF(finalcr) {region R=B->Mark(N.i)-B->dot; line*L; B->changed=1;
  88. for(L=R.beg.r;!L?0:L!=R.end.r;L=L->next) {L->no_cr(0); crcheck(L); L->la(1);}}
  89. /*-----*/
  90. KF(nofinalcr) {region R=B->Mark(N.i)-B->dot; line*L; B->changed=1;
  91. for(L=R.beg.r;!L?0:L!=R.end.r;L=L->next) {L->no_cr(1); crcheck(L); L->la(1);}}
  92. /*-----*/
  93. KF(delet) {int i;
  94. if(N.i>=0) for(i=0;i<N.i;i++) !B->dot; else for(i=0;i>N.i;i--) *B+=' ';}
  95. /*-----*/
  96. KF(insertspaces) {delet(-N);}
  97. /*-----*/
  98. KF(goright) {int i;
  99. if(N.i>=0) for(i=0;i<N.i;i++) B->right(); else for(i=0;i>N.i;i--) B->left();}
  100. /*-----*/
  101. KF(goleft) {goright(-N);}
  102. /*-----*/
  103. KF(godown) {int i; B->dotcc=B->dotcc2;
  104. if(N.i>=0) for(i=0;i<N.i;i++) B->down(); else for(i=0;i>N.i;i--) B->up();}
  105. /*-----*/
  106. KF(goup) {godown(-N);}
  107. /*-----*/
  108. KF(godownpart){int i=0,j,k,n=N.i,p; line*L;
  109. if(!B->longlines) {godown(N); return;} if(n<0) {gouppart(-N,T1); return;}
  110. j=linewhere(B->dot); if(!n) goto X; p=B->dot.r->nparts();
  111. LOOP: i++; j+=gp_Cols; if(k=(j<p*gp_Cols)) if(i<n) goto LOOP;
  112. if(!k) if(L=B->dot.r->next) {
  113.     B->dot.r=L; j%=gp_Cols; if(i<n) {p=L->nparts(); goto LOOP;}}
  114. X: if(T1.n==_int) j=(j/gp_Cols)*gp_Cols+(T1.i>?0);
  115. B->dot.c=B->dot.r->from_tabexp(j-2*(j/gp_Cols));}
  116. /*-----*/
  117. KF(gouppart){int i=0,j,k,n=N.i; line*L;
  118. if(!B->longlines) {goup(N); return;} if(n<0) {godownpart(-N,T1); return;}
  119. j=linewhere(B->dot); if(!n) goto X;
  120. LOOP: i++; j-=gp_Cols; if(j>=0) if(i<n) goto LOOP;
  121. if(j<0) if(L=B->dot.r->prev) {
  122.     B->dot.r=L; j+=L->nparts()*gp_Cols; if(i<n) goto LOOP;}
  123. X: if(T1.n==_int) j=(j/gp_Cols)*gp_Cols+(T1.i>?0);
  124. B->dot.c=B->dot.r->from_tabexp(j-2*(j/gp_Cols));}
  125. /*-----*/
  126. KF(gotobol) {B->dot.c=0; B->dotcc=B->dotcc2=-1;}
  127. /*-----*/
  128. KF(gotoeol) {B->dot.c=B->dot.r->n; B->dotcc=B->dotcc2=-1;}
  129. /*-----*/
  130. KF(gotocol) {if(N.i<=0 ?1: B->twod ?0: N.i>B->dot.r->n) MOAN("no such column");
  131. goright(N.i-B->dot.c-1,1); B->dotcc=B->dotcc2=-1;}
  132. /*-----*/
  133. KF(whoa) {beep(); MOAN("aborted");}
  134. /*-----*/
  135. KF(backspace) {int i; for(i=0;i<N.i;i++) B->dot.bs();}
  136. /*-----*/
  137. KF(tabulate) {int i; if(B->tabtype) Insert(N.i,9);
  138.     else for(i=N.i;i>0;i--) Insert(sptotab(B->dot.c)+1,' ');}
  139. /*-----*/
  140. KF(kill_to_eol) {int i,j; line*L; obtype=ob_kill; mark Q=B->dot;
  141. if(N.i>=0) {for(i=0;i<N.i;i++) if(Q.c<(j=Q.r->n)) Q.c=j;
  142.     else if(L=Q.r->next) {Q.r=L; Q.c=0;} else break;}
  143. else     {for(i=0;i>N.i;i--) if(Q.c>0) Q.c=0;
  144.     else if(L=Q.r->prev) Q.c=(Q.r=L)->n; else break;} (B->dot-Q).kill();}
  145. /*-----*/
  146. KF(refresh_display){line*L;
  147. if(!N.n){if(B->longlines) B->refresh=1; N.i=B->nrows/2;}
  148. if(N.i>=0) {for(L=B->dot.r;L->prev?N.i>1:0;N.i--,L=L->prev); B->start.r=L;}
  149. int i; if(!N.n?1:N.i<0) for(i=0;i<gp_Rows;i++) Sl[i].ok=0;}
  150. /*-----*/
  151. KF(openline) {int i; for(i=0;i<N.i;i++) B->dot/0;}
  152. /*-----*/
  153. int charfrommenu() {int i,j,K,k,m,n,z=0; mousestate ms; ms=Jerry; Jerry.mc=1;
  154. for(i=0;i<=16;i++) {gp_clear(i); Sl[i].ok=0;} /* menu */
  155. display("\030 \031 \033 \032 select which char, End aborts, Return chooses",
  156.   16,0,Cyan+8); Jerry.range(16,64);
  157. for(i=0;i<8;i++) for(j=0;j<32;j++) scr(i+i,j+j+j/8)=sch(i*32+j,Orange); K=k=112;
  158. A: k&=0xff; if(z!=-mousemove) Jerry.move(2*(k>>5),2*(k&31));
  159. m=(k/16)|1; n=2*(k&31)+(k&24)/8; scr(m,n)=sch('\030',Green+8); K=k;
  160. switch(z=getkey()) {
  161. case -leftarrow:  k--; break;
  162. case -rightarrow: k++; break;
  163. case -uparrow:    k-=32; break;
  164. case -downarrow:  k+=32; break;
  165. case -mousemove:  k=(Jerry.x/2)+32*(Jerry.y/2); break;
  166. case -end: case -rbutton: case -mbutton: Jerry=ms; return -1;
  167. case CR: case -lbutton: Jerry=ms; return k;}
  168. if(K!=k) scr(m,n)=sch(' ',White); goto A;}
  169. /*-----*/
  170. KF(literalchar) {int c,i; if(play) return; mousestate ms; ms=Jerry;
  171. display("literal character (alt-0 for ascii-zero, ctrl-tab for menu of chars)",
  172.   B->lastrow,0,Cyan); c=getkey(); B->redraw_info();
  173. Y: switch(c) {
  174. case -mousemove: case -lbuttond: case -mbuttond: case -rbuttond:
  175.     c=getkey(); goto Y;
  176. case LF:  for(i=0;i<N.i;i++) {B->dot/1; B->dot.r->prev->no_cr(1);}
  177.     setref(f,&linefeed); Jerry=ms; return;
  178. case -ctrl_tab: case -lbutton: case -mbutton: case -rbutton:
  179.     if((c=charfrommenu())<0) {basemi.rec=0; Jerry=ms; return;} goto X;
  180. case -alt_0: c=0; X:
  181. default: Jerry=ms;
  182.     if(c>=0) {setref(f,&insert); setrek(T1,(char)c); Insert(N.i,c); return;}
  183.     pr(CW,"%s is not an ASCII char",altnames[-c]?:"this"); MOAN(CW);}}
  184. /*-----*/
  185. KF(times4) {int j; if(play) return;
  186. j=B->lastrow; pr(CW,"numeric arg: %1d",N.i*4); display(CW,j,0,Cyan);
  187. Sl[j].ok=0; Obey(val(N.i*4,_int));}
  188. /*-----*/
  189. KF(killregion) {obtype=ob_kill; (B->Mark(N.i)-B->dot).kill();}
  190. /*----- convert char to as in C string */
  191. KF(cstrchr) {line*L=B->dot.r; int i,n=B->dot.c;
  192. if(n>=L->n) {*B+='\\'; *B+='n'; !B->dot;}
  193. else if(!iscntrl(i=L->s[n]&255)) {if(i=='"' ?1: i=='\\') *B+='\\'; B->right();}
  194. else {*B+='\\'; *B+='0'+i/64; i%=64; *B+='0'+i/8; *B+='0'+i%8; !B->dot;}}
  195. /*----- convert char from as in C string */
  196. KF(cchrstr) {int i,j,n; line*L; if((n=B->dot.c)>=(L=B->dot.r)->n) return;
  197. if(L->s[n]!='\\') {B->right(); return;} !B->dot; if(n>=L->n) return;
  198. switch(i=L->s[n]){
  199. case 'n': !B->dot; *B+=char(LF); break;
  200. case 't': !B->dot; *B+='\011'; break;
  201. case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7':
  202.     !B->dot; j=i-'0';
  203.     if(n<L->n) if(i=L->s[n]-'0',i>=0) if(i<8) {!B->dot; j=j*8+i;
  204.     if(n<L->n) if(i=L->s[n]-'0',i>=0) if(i<8) {!B->dot; j=j*8+i;}}
  205.     *B+=(char)j; break;
  206. default: !B->dot; B->right(); break;}}
  207. /*-----*/
  208. KF(showinfo) {line*L,*K=B->dot.r; int i=0,j=0,k=0,n,w; char*T;
  209. for(L=B->text.next;L;L=L->next) {i++; j+=(L->n+(L->no_cr()?1:2)); if(K==L) k=i;}
  210. j-=2; L=B->dot.r; T=L->s; n=B->dot.c; w=L->to_tabexp(L->n);
  211. pr(disp,"line %1d of %1d, char %1d of %1d(%1d), %1d bytes, at ",
  212.   k,B->text.prev->n?i:i-1,n+1,L->n,w,j);
  213. if(n<L->n) pa(disp,"'%c' = %1d",T[n]?:' ',(byte)T[n]);
  214. else pa(disp,k==i?"eof":"eol"); pa(disp,"; altM gives modes"); Display=disp;}
  215. /*-----*/
  216. KF(savebuffer) {B->write();}
  217. /*-----*/
  218. KF(writebuffer) {T1.getifn(Fn,"file to write to",_buffer); setrek(T1,T1.copy());
  219. if(fileexists(T1.s)) if(!yesno("file exists: OK to overwrite it?")) return;
  220. if(buf_named(T1)) MOAN("this file already has a buffer");
  221. buffer *BB=B; Text U; (new buffer(T1.s,0))->go_to();
  222. U=Text(BB->text.next,BB->text.prev).copy(); B->text.next->del();
  223. B->text.next=U.beg; B->text.prev=U.end; B->dot=mark(B->text.next,0);
  224. if(N.i>0) B->write(); BB->go_to();}
  225. /*-----*/
  226. static buffer *buffertolose=0;
  227. /*-----*/
  228. void losebuffer(val&k){if(k.n==_buffer) if(k.b==buffertolose) {k.b=0; k.n=0;}}
  229. /*-----*/
  230. int deletebuffer(buffer*C) {buffer*A,*BB; if(!C->nrows) goto Y;
  231. for(BB=B->next;BB;BB=BB->next) if(!BB->nrows) goto Y;
  232. for(BB=bhead;BB?BB!=B:0;BB=BB->next) if(!BB->nrows) goto Y; beep(); return 0;
  233. Y: if(C->changed) if(!yesno(
  234.   "This buffer changed since saved last: shall I still drop it?")) return 0;
  235. Z: buffertolose=C; keys.search(&losebuffer);
  236. if(C->nrows) {A=B; B=C; BB->go_to(); if(A!=C) B=A;} delete C; return 1;}
  237. /*-----*/
  238. KF(delbuf) {deletebuffer(B);}
  239. /*-----*/
  240. KF(finish) {buffer *BB; char*q="%s changed: exit without saving it?";
  241. A: forallbufs(BB) if(BB->changed) break;
  242. if(BB) {pr(CW,q,BB->name); if(!yesno(CW)) return; BB->changed=0; goto A;}
  243. if(appendixsize>1) if(!yesno("exit without saving the dictionary's appendix?"))
  244.   return;
  245. clearscreen(); gp_cursor(gp_cur(0,0)); exit(1);}
  246. /*-----*/
  247. KF(setrightmargin) {
  248. if(N.n) B->rmargin=N.i<0?(N.i>-11?-gp_Cols:N.i):N.i>11?N.i:gp_Cols;
  249. if(B->rmargin>=0) pr(disp,"right margin = %1d",B->rmargin);
  250. else pr(disp,"right margin = %1d 'n'-widths proportional",-B->rmargin);
  251. Display=disp;}
  252. /*-----*/
  253. KF(pushmark) {if(B->nmarks()>16) MOAN("this buffer has too many marks");
  254. B->dot.push();}
  255. /*-----*/
  256. KF(swopmark) {if(N.i-1==B->nmarks()) B->dot.hsup();
  257. else {mark*M=&B->Mark(N.i),Q=B->dot; B->dot=*M; *M=Q;}}
  258. /*-----*/
  259. KF(setmark) {if(N.i-1==B->nmarks()) B->dot.hsup(); else B->Mark(N.i)=B->dot;}
  260. /*-----*/
  261. KF(markbof) {mark Q=B->bof();
  262.     if(N.i-1==B->nmarks()) Q.hsup(); else B->Mark(N.i)=Q;}
  263. /*-----*/
  264. KF(markeof) {mark Q=B->eof();
  265.     if(N.i-1==B->nmarks()) Q.hsup(); else B->Mark(N.i)=Q;}
  266. /*-----*/
  267. KF(popmark) {B->dot.pop();}
  268. /*-----*/
  269. KF(remmark) {int i; for(i=0;i<N.i;i++) B->rem1mark();}
  270. /*-----*/
  271. KF(showregion) {if(!N.i) (B->Mark(1)-B->Mark(2)).color(White,Magenta);
  272. else (B->Mark(N.i)-B->dot).color(White,Magenta);}
  273. /*-----*/
  274. KF(yank) {obtype=ob_yank;
  275. lastyank=B->dot.yank(killring[nkill]); lastyank.color(White,Magenta);
  276. if(N.n) if(N.i-1==B->nmarks()) lastyank.beg.hsup();
  277.    else B->Mark(N.i)=lastyank.beg;}
  278. /*-----*/
  279. KF(replyank) {if(prevobtype!=ob_yank) {yank(val(1,0),T1,T2); return;}
  280. obtype=ob_yank; nkill-=N.i; nkill&=15;
  281. lastyank=lastyank.repl(killring[nkill],1); lastyank.color(White,Magenta);}
  282. /*-----*//* still no way in Gnu C to tell if a drive is there/usable or not */
  283. int attrib(char*file){if(isalpha(file[0]))if(file[1]==':')if(!file[2])return 16;
  284. _ax=0x4300; _dx=(int)file; int21(); if(_carry) return 256*_ax; return _cx;}
  285. /*----- replace all T1 by T2 between dot and Nth mark */
  286. void Replace(val N,val T1,val T2,char *prompt,int ask,int word){
  287. T1.getifn(T1t,prompt,_magic); setrek(T1,T1.copy());
  288. T2.getifn(T2t,"by:");         setrek(T2,T2.copy());
  289. mark M=B->Mark(N.i); (M-B->dot).replace(T1,T2,ask,word);}
  290. /*-----*/
  291. KF(repl)        {Replace(N,T1,T2,"rep:"         ,0,0);}
  292. KF(replword)    {Replace(N,T1,T2,"rep word:"    ,0,1);}
  293. KF(replask)     {Replace(N,T1,T2,"rep ask:"     ,1,0);}
  294. KF(replwordask) {Replace(N,T1,T2,"rep word ask:",1,1);}
  295. /*----- move char by N.i positions */
  296. KF(twiddle) {int i,j,n; line*L=B->dot.r; char*T=L->s;
  297. if(N.i>0) for(i=0;i<N.i;i++) {L->la(1);
  298.     if((n=B->dot.c)+1>=L->n) MOAN("can't twiddle-chars across line end");
  299.     j=T[n]; T[n]=T[n+1]; T[n+1]=j; B->dot.c++; }
  300. else for(i=0;i>N.i;i--) {
  301.     if((n=B->dot.c)<=0) MOAN("can't twiddle-chars across line end");
  302.     j=T[n]; T[n]=T[n-1]; T[n-1]=j; B->dot.c--; L->la(1); }; B->changed=1;}
  303. /*----- look for T1 starting at dot. If N.i set, stop at Nth mark */
  304. void search(val N,val T1,char*prompt,int back=0,int word=0){int i,n,x;
  305. T1.getifn(T1t,prompt,_magic); setrek(T1,T1.copy());
  306. if((B->dot-(N.n?B->Mark(N.i):back?B->bof():B->eof())).hunt(T1,back,word)) {
  307.     B->dot=back?Found.beg:Found.end; Found.color(White,Magenta);}
  308. else {strcpy(CW,"not found '"); /* display /000 as space here */
  309.     for(n=(T1.n&0x00ffffff)<?(strsize-12),i=0;i<n;i++) CW[i+11]=T1.s[i]?:' ';
  310.     strcpy(CW+n+11,"'"); MOAN(CW);}}
  311. /*-----*/
  312. KF(findf)     {search(N,T1,"find:"          ,0,0);}
  313. KF(findb)     {search(N,T1,"find back:"     ,1,0);}
  314. KF(findwordf) {search(N,T1,"find word:"     ,0,1);}
  315. KF(findwordb) {search(N,T1,"find word back:",1,1);}
  316. /*----- incremental search starting at dot. If N.i set, stop at Nth mark */
  317. void incrsearch(val N,char*pt,int back=0){line *L; region where[64+1];
  318. int p=strlen(pt),sl=B->lastrow,at=gp_Attr,c,i; mark whoa,start,dot,M;
  319. where[0]=B->dot-B->dot; Found=where[0]; T1t.n=0; T1t.s=T1w;
  320. whoa=N.n?B->Mark(N.i):back?B->bof():B->eof(); start=B->start; dot=B->dot;
  321. GETCHAR: displayn(pt,sl,0,Magenta); display(T1t,sl,p,Cyan);
  322. cursor.r=sl; cursor.c=(p+T1t.n)<?(gp_Cols-1); gp_cursor(cursor);
  323. switch(c=getkey()) {
  324. case -ins: if(!T1t.n) goto GETCHAR; M=back?Found.beg:Found.end; goto HUNT;
  325. case -del: if(!T1t.n) goto GETCHAR; Found=where[--T1t.n]; goto DISP;
  326. case -alt_end: Moan="user abort"; goto OUT;
  327. case -alt_ret: c=CR; goto C;
  328. case -pagedown: goto OUT; /* end input */
  329. default: if(c<=0) goto GETCHAR; if(c==CR) c=LF; /* so RET gives newline */
  330. C:  if(T1t.n>=64) {Moan="incremental search string too long"; goto OUT;}
  331.     if(back) {M=Found.end; ++M; if(!M.r) M=Found.end;} else M=Found.beg;
  332.     T1t.s[T1t.n++]=c;}
  333. HUNT: if(Moan==offscreen) Moan=0;
  334. if(!(M-whoa).hunt(T1t,back,0)) beep(); where[T1t.n]=Found;
  335. DISP: gp_Attr=at; B->dot=back?Found.beg:Found.end; Found.color(White,Magenta);
  336. B->dotcc=B->dotcc2=-1; Sl[B->lastrow].ok=1; B->display(); goto GETCHAR;
  337. OUT: gp_Attr=at; Sl[sl].ok=0; T1t.s[T1t.n]=0; B->start=start;
  338. B->dotcc=B->dotcc2=-1; if(Moan) {Found=where[0]; B->dot=dot; MOAN(Moan);}
  339. Sl[B->lastrow].ok=0; if(back) setref(f,&findb); else setref(f,&findf);
  340. setrec(T1,T1t.copy());}
  341. /*-----*/
  342. KF(incrfindf) {incrsearch(N,"incr find:"     ,0);}
  343. KF(incrfindb) {incrsearch(N,"incr find back:",1);}
  344. /*----- read esc-and-number */
  345. void readescno(short c){if(play) return; int i,j,N; short d=c;
  346. i=-1; B->display(); N=c=='-'?0:c-'0'; j=B->row1+B->nrows-1;
  347. CC: i++; pr(CW,"numeric arg: %c%1d",d=='-'?'-':' ',c=='-'?1:N);
  348. display(CW,j,0,Cyan); gp_cursor(cursor); c=getkey();
  349. if(c<'0'?0:c<='9') {N=10*N+c-'0'; goto CC;} else nextch=c;
  350. Sl[j].ok=0; if(d=='-') if(!i) N=-1; else N=-N; Obey(val(N,_int));}
  351. /*-----*/
  352. KF(esc0) {readescno('0');} KF(esc1) {readescno('1');} KF(esc2) {readescno('2');}
  353. KF(esc3) {readescno('3');} KF(esc4) {readescno('4');} KF(esc5) {readescno('5');}
  354. KF(esc6) {readescno('6');} KF(esc7) {readescno('7');} KF(esc8) {readescno('8');}
  355. KF(esc9) {readescno('9');} KF(escminus) {readescno('-');}
  356. /*----- read alt-number */
  357. void readaltno(short c){if(play) return; int i,j,k,N; short d=c;
  358. i=-1; B->display(); N=c=='-'?0:c-'0'; j=B->row1+B->nrows-1;
  359. C: i++; pr(CW,"numeric arg: %c%1d",d=='-'?'-':' ',c=='-'?1:N);
  360. display(CW,j,0,Cyan); gp_cursor(cursor); c=getkey();
  361. if(c==-alt_0) {N=10*N; goto C;}
  362. else if(-c>=alt_1?-c<=alt_9:0) {N=10*N-c+1-alt_1; goto C;} else nextch=c;
  363. Sl[j].ok=0; if(d=='-') if(!i) N=-1; else N=-N; Obey(val(N,_int));}
  364. /*-----*/
  365. KF(alt0) {readaltno('0');} KF(alt1) {readaltno('1');} KF(alt2) {readaltno('2');}
  366. KF(alt3) {readaltno('3');} KF(alt4) {readaltno('4');} KF(alt5) {readaltno('5');}
  367. KF(alt6) {readaltno('6');} KF(alt7) {readaltno('7');} KF(alt8) {readaltno('8');}
  368. KF(alt9) {readaltno('9');} KF(altminus) {readaltno('-');}
  369. /*----- modemenu recorded in macro as calls of these */
  370. KF(tabmode) {int i; B->tabtype=(N.i>?0)<?2; for(i=0;i<gp_Rows;i++) Sl[i].ok=0;}
  371. KF(twodmode) {B->twod=(N.i>?0)<?1;}
  372. KF(overlaymode) {B->overlay=(N.i>?0)<?2;}
  373. KF(wrapmode) {B->wrap=(N.i>?0)<?1;}
  374. KF(casemode) {B->Case=(N.i>?0)<?1;}
  375. KF(longlinesmode) {int i;
  376.     B->longlines=(N.i>?0)<?1; for(i=0;i<gp_Rows;i++) Sl[i].ok=0;}
  377. KF(skipafterwordmode) {B->skip_after_word=(N.i>?0)<?3;}
  378. KF(cccmode) {ccc=(N.i>?0)<?1;}
  379. /*----- ith mode */
  380. byte &bufmode(int i,buffer*BB/*=0*/){if(!BB) BB=B;
  381. switch(i<0?0:i%buffer_nmodes){
  382. case  0: return BB->tabtype;
  383. case  1: return BB->twod;
  384. case  2: return BB->overlay;
  385. case  3: return BB->wrap;
  386. case  4: return BB->Case;
  387. case  5: return BB->longlines;
  388. case  6: return BB->skip_after_word;} return BB->tabtype;}
  389. /*-----*/
  390. char**dispmode[]={
  391. (char*[]){" tab shown as one char",
  392.       " tab obeyed",
  393.       " tab shown and obeyed",0},
  394. (char*[]){" going off end of line goes to next line",
  395.       " going off end of line appends spaces to line",0},
  396. (char*[]){" typed char inserted",
  397.       " typed char overlays, cursor moves",
  398.       " typed char overlays, cursor stays still",0},
  399. (char*[]){" no auto newline on typing long text lines",
  400.       " auto newline on typing long text lines",0},
  401. (char*[]){" in search, ignore case of letters",
  402.       " in search, don't ignore case of letters",0},
  403. (char*[]){" horiz scroll to show cursor in long lines",
  404.       " display long lines folded",0},
  405. (char*[]){" don't skip nonword chars after skipping word",
  406.       " nonword chars belong to word to left",
  407.       " nonword chars belong to word to right",
  408.       " skip nonword chars after skipping word",0},0};
  409. /*-----*/
  410. KF(modemenu) {int c=0,i,j,n; byte *T; B->dotcc=B->dotcc2=-1; mousestate ms;
  411. if(play) MOAN("modemenu called by macro"); macstep step; basemi.rec=0;
  412. static subr *mf[]={&tabmode, &twodmode, &overlaymode, &wrapmode, &casemode,
  413.     &longlinesmode, &skipafterwordmode}; buffer*BB; step=macstep();
  414. for(i=0;i<gp_Cols;i++) Sl[i].ok=0; j=0; n=buffer_nmodes; ms=Jerry; Jerry.mc=1;
  415. C: for(i=0;i<buffer_nmodes;i++) display(dispmode[i][bufmode(i)],i,0,Orange+8);
  416. display("(\030 and \031 move, ret changes mode, any other key exits)",
  417.   i,0,Green+8); Jerry.range(buffer_nmodes,4); Jerry.bd=0;
  418. display("(ctrl-B copies all the modes from some other buffer's modes)",i+1,0,
  419.   Green+8);
  420. A: if(step.f.n) if(record) {(*record)+=step.copy(); step.del(); step.clear();}
  421. if(c!=-mousemove) Jerry.move(j,0); scr(j,0)=sch(2,White);
  422. switch(c=getkey()) {
  423. case -mousemove: scr(j,0)=sch(' ',White); j=Jerry.y; goto A;
  424. case -downarrow: scr(j,0)=sch(' ',White); j=(j+1  )%n; goto A;
  425. case -uparrow:   scr(j,0)=sch(' ',White); j=(j-1+n)%n; goto A;
  426. case 'B'-64: Fn.s[0]=0; Fn.n=0; copybufmodes(val(1,0),Fn);
  427.     step.f=kf(©bufmodes); step.N=val(1,0); step.T1=val("",0); step.T2=val();
  428.     display(" ",B->lastrow,0,0); Fn.s=0; goto C;
  429. case CR: case -lbutton: T=&bufmode(j,B); (*T)++; if(!dispmode[j][*T]) *T=0;
  430.     display(dispmode[j][*T],j,0,Orange+8);
  431.     step.f=kf(mf[j]); step.N=val(*T,_int);step.T1=val();step.T2=val(); goto A;}
  432. Jerry=ms;}
  433. /*-----*/
  434. KF(copybufmodes){int i; buffer*C=get_file(T1,"copy modes from buffer:");
  435. if(!C) MOAN("copybufmodes can't find buffer");
  436. for(i=0;i<buffer_nmodes;i++) bufmode(i,B)=bufmode(i,C);
  437. setrek(T1,val(copyof(C->name)));}
  438. /*-----*/
  439. void insert_(int N,byte c){Insert(N,c);}
  440. /*-----*/
  441. void overlay_(int N,byte c){int i; for(i=0;i<N;i++) {B->dot=c; goright(1,1);}}
  442. /*-----*/
  443. void nomove_(int N,byte c){int i; for(i=0;i<N;i++) B->dot=c;}
  444. /*-----*/
  445. KF(insert) {int i,j,k; if(T1.n==_char) {insert_(N.i,val(T1).i); return;}
  446. T1.getifn(T1t,"text to insert:"); setrek(T1,T1.copy()); j=T1.n; char*s;
  447. for(k=0;k<N.i;k++) for(s=T1.s,i=0;i<j;i++) *B+=*s++;}
  448. /*-----*/
  449. KF(overlay) {int i,j,k; if(T1.n==_char) {overlay_(N.i,val(T1).i); return;}
  450. T1.getifn(T1t,"text to overlay:"); setrek(T1,T1.copy()); j=T1.n; char*s;
  451. for(k=0;k<N.i;k++) for(s=T1.s,i=0;i<j;i++) {B->dot=*s++; goright(1,1);}}
  452. /*-----*/
  453. KF(nomove) {int i,j,k; if(T1.n==_char) {nomove_(N.i,val(T1).i); return;}
  454. T1.getifn(T1t,"text to overlay_no_move:"); setrek(T1,T1.copy()); j=T1.n; char*s;
  455. for(k=0;k<N.i;k++) for(s=T1.s,i=0;i<j;i++) B->dot=*s++;}
  456. /*-----*/
  457. /* int Gets(char*s,int n,FILE*F){int i; fgets(s,n,F);
  458. if(i=strlen(s)) if(s[i-1]==LF) s[--i]=0; return i;} */
  459. /*-----*/
  460. char*helphelp[]={"which key to type now to get what help:-",
  461. "?   this information",
  462. "a   all 'one-line help' lines which contain a particular string",
  463. "d   help about use of special keys in directory menus",
  464. "i   help about use of special keys in incremental search",
  465. "L   explanation of symbols used in help information",
  466. "l   long help about any one subroutine",
  467. "m   help about magic characters",
  468. "o   help about allowed operator uses in macros",
  469. "r   help about the replace commands",
  470. "s   help about use of alt- and special keys when inputting a string argument",
  471. "(Any other keysequence gets one-line help about that keysequence)",
  472. "(For the mouse, see section [MOUSE] in file README)",0};
  473. /*-----*/
  474. char*incrhelp[]={"effect of alt- and special keys in incremental search:-",
  475. "insert     look again for this same string",
  476. "delete     cancel effect of typing last displayed character",
  477. "altend     abort search",
  478. "pagedown   exit from search (NB. The search string can't be > 64 chars long)",
  479. "altret     look for CR stored as byte (not as bit) in AAEMACS's line image",
  480. "ret or ctrl-J or ctrl-M    look for end-of-line",
  481. 0};
  482. /*-----*/
  483. char*replhelp[]={"effect of replies to 'shall I replace here?' in replace:-",
  484. "space      yes and look for the next replacing",
  485. "N  or  n   no  and look for the next replacing",
  486. ".          yes and exit",
  487. "altend     no  and exit",
  488. "end        no  and exit and leave the cursor here",
  489. 0};
  490. /*-----*/
  491. char*dirmenuhelp[]={"effect of alt- and special keys in directory-menus:-",
  492. "\030 \031        move pointer in menu",
  493. "pageup     move pointer in menu",
  494. "pagedown   move pointer in menu",
  495. "insert     select new buffer (you will be asked for its name)",
  496. "ctrlinsert create new directory (you will be asked for its name)",
  497. "delete     delete this PC file or directory (if directory, must be empty)",
  498. "home       go to parent directory",
  499. "alt-K      copy this directory to kill ring (online & with ctrl-X ctrl-F)",
  500. "alt-R      rename file (not buffer)",
  501. "alt-del    drop this file's buffer, if it has one",
  502. "ctrl-N     sort by name",
  503. "ctrl-S     sort by size",
  504. "ctrl-D     sort by date",
  505. "ctrl-X     don't sort",
  506. "altend     abort",
  507. "return     choose this file                 or left mouse button",
  508. "F1         get submenu of these commands    or right mouse button",
  509. 0};
  510. /*-----*/
  511. char*magichelp[]={"effect of magic characters in searching:-",
  512. ".          any one character except LF",
  513. ",          any one letter or number or _",
  514. "space      one or more spaces and/or tabs   (Note how magic space is shown)",
  515. "\011 (tab)    one or more spaces and/or tabs and/or LF's",
  516. "|          separates alternatives",
  517. "[     ]    start & end of a set of alternatives",
  518. "#          any one character not a letter or number or '_'",
  519. "\\          beginning or end of file",
  520. "/          LF or beginning or end of file",
  521. "{     }    set start & end of 'string found' (default = all matched chars)",
  522. "lowercase letter       uppercase or lowercase of that letter",
  523. "=          the rest of the current line (not any LF at its end)",
  524. "Magic search is quicker if the first character in the search string is not \
  525. magic",
  526. 0};
  527. /*-----*/
  528. char**infohelp=0,**infobig=0;
  529. char**Subrhelp(char*name){int i,n=strlen(name); char*s;
  530. if(!infobig) {infobig=readtext(bighelpfile);
  531.     if(!infobig) {pr(CW,"I can't find %s",bighelpfile); Moan=CW; return 0;}}
  532. for(i=0;s=infobig[i];i++) if(s[0]=='{') if(!strncmp(s+1,name,n))
  533.   if(s[n+1]==','?1:s[n+1]=='}') return infobig+i;
  534. pr(CW,"no long help for subroutine %s",name); Moan=CW; return 0;}
  535. /*-----*/
  536. KF(help) {int i,j,k,kc,l,m,n,p; char *s,*T,cw[256],*y,**u;
  537. if(!play) basemi.rec=0;
  538. val f; Subr*sub; char*Z="type '?', or key sequence that help is wanted for:";
  539. if(T1.s) f=T1.keyseq(); else f=getkeyseq(Z); if(f.n==_bad) MOAN(f.s);
  540. LOOP: pr(cw,"%k :: ",&keyseq); n=strlen(cw); kc=keyseqc[keyseqc[0]-1];
  541. if(keyseqc[0]!=2 ?: kc<32) switch(f.n){ /* if not printable */
  542. default:cw[n-3]=0;pr(CW,"BUG: %sbound to a %s",cw,f.n>0?"string":keysort[-f.n]);
  543.     Display=CW; return;
  544. case 0: pr(CW,f.s?"BUG: %sbound to empty string":"%sis unbound",cw);
  545.     Display=CW; return;
  546. case _subr: if(!infohelp) {infohelp=readtext(helpfile);
  547.     if(!infohelp) {pr(CW,"I can't find %s",helpfile); Moan=CW; return;}}
  548.     for(i=0;s=infohelp[i];i++) if(!strncmp(s,cw,n)) {Display=s; return;}
  549.     Moan="no help for this key"; return;
  550. case _macro: pr(CW,"%sbound to a macro",cw); Display=CW; return;
  551. case _keyarray: Display="BUG: this key sequence is not complete"; return;
  552. case _buffer: pr(CW,"%sbound to buffer %s",cw,f.b->name); Display=CW; return;
  553. case _int: pr(CW,"BUG: %sbound to integer %1d",cw,f.i); Display=CW; return;}
  554. display(" ",B->lastrow,0,Orange);
  555. switch(kc){ /* if printable */
  556. default: pr(CW,"inserts or overlays '%c' according to mode of buffer",kc);
  557.     Display=CW; return;
  558. case '?': for(j=0;T=helphelp[j];j++) display(T,j,0,Green);
  559.     f=getkeyseq(Z); refreshscreen(); goto LOOP;
  560. case 'a': if(!infohelp) {infohelp=readtext(helpfile);
  561.     if(!infohelp) {pr(CW,"I can't find %s",helpfile); Moan=CW; return;}}
  562.     for(m=0;infohelp[m];m++); y=new char[m]; for(i=0;i<m;i++) y[i]=0; T1.n=0;
  563.     T1.s=0; T1.getifn(T1t,"apropos:"); for(p=j=i=0;s=infohelp[i];i++) {
  564.     for(k=strlen(s)-T1.n,l=0;l<=k;l++) if(caseq(T1,val(s+l,T1.n))) goto X;
  565.     continue; X: y[i]=1; p++;}
  566.     if(!p) {pr(CW,"Nothing found. For help, read file %s\\README",DIR); Moan=CW;
  567.     delete y; return;}
  568.     for(j=i=0;i<m;i++) if(y[i]) {
  569.     if(j==gp_Rows-1){display("(More)",j,0,Green); getkey(); j=0;}
  570.     display(infohelp[i],j++,0,Orange);}
  571.     delete y; break;
  572. case 'd': for(j=0;T=dirmenuhelp[j];j++) display(T,j,0,Orange); break;
  573. case 'i': for(j=0;T=incrhelp[j];j++) display(T,j,0,Orange); break;
  574. case 'l': sub=subrmenu("subroutine to get help for?"); B->display();
  575.     if(!(u=Subrhelp(sub->name))) return; j=0; display(*u++,j++,0,Orange);
  576.     while(*u?**u!='{':0) display(*u++,j++,0,Orange);
  577.     display("(type 'ctrl-_ L' to find about the symbols)",j++,0,Green); break;
  578. case 'L': if(!infobig) {infobig=readtext(bighelpfile);
  579.     if(!infobig) {pr(CW,"I can't find %s",bighelpfile); Moan=CW; return;}}
  580.     for(j=i=0;(s=infobig[i])?strncmp(s,"----",4):0;i++) display(s,j++,0,Orange);
  581.     break;
  582. case 'm': for(j=0;T=magichelp[j];j++) display(T,j,0,Orange); break;
  583. case 'o': j=display_op_uses(); break;
  584. case 'r': for(j=0;T=replhelp[j];j++) display(T,j,0,Orange); break;
  585. case 's': for(j=0;T=getstringhelp[j];j++) display(T,j,0,Orange); break;}
  586. display("(type ctrl-_ for more help, any other char to continue)",j,0,Green);
  587. if(getkey()=='_'-64) {f=getkeyseq(Z); refreshscreen(); goto LOOP;}}
  588. /*----- obey subr for all bound key entries */
  589. void forallkeys(void fn(val*),int L/*=1*/,keyarray&K/*=keys*/){int k; val*f;
  590. for(k=0;k<K.n;k++){keyseqc[0]=L+1; f=&K.a[(byte)(keyseqc[L]=k)];
  591.     if(f->n) if(f->n==_keyarray) forallkeys(fn,L+1,*f->k); else fn(f);}}
  592. /*-----*/
  593. void moan_if_no_help(val*f){char **info,*s,cw[128],H[128]; int i,j;
  594. pr(cw,"%k :: ",&keyseq); j=strlen(cw);
  595. info=readtext(helpfile); if(!info){pr(CW,"I can't find %s",helpfile); MOAN(CW);}
  596. for(i=0;s=info[i];i++) if(!strncmp(s,cw,j)) goto E;
  597. *B+=cw; *B+=" has no help\n"; E: delete info[0]; delete info;}
  598. /*-----*/
  599. void prbuffer(buffer*C){
  600. if(C->bound.n) pb("#buffer(%S,%K);\n",C->name,&C->bound);
  601. else pb("#buffer(%S);\n",C->name);}
  602. /*-----*/
  603. void print_subr(val*f){pb("%k :: ",&keyseq);macstep(*f,1,0).print(); newline();}
  604. /*-----*/
  605. KF(checkhelp) {forallkeys(moan_if_no_help);}
  606. /*-----*/
  607. KF(prbuffers) {buffer*C; forallbufs(C) prbuffer(C);}
  608. /*-----*/
  609. KF(prbindings) {forallkeys(print_subr);}
  610. /*-----*/
  611. Subr*subrmenu(char*s){int x=0,y=0,X,Y,c,I,J,K,i,j=0,k=0,m,n,w=gp_Rows-1; Subr*S;
  612. mousestate ms; ms=Jerry; Jerry.mc=1; B->dotcc=-1;
  613. for(n=0;subrname[n].n;n++); m=subrname[n-1].menur+1;
  614. D: for(i=0;S=&subrname[i],S[0].name;i++)
  615.   if((K=S->menur-k)>=0) if(K<w) {
  616.     display(" ",K,S->menuc,Orange+8); display(S->name,K,S->menuc+1,Orange+8);}
  617. pr(CW,"%s (\030 \031 \032 \033 select, end aborts, any other key decides)",s);
  618. display(CW,w<?=m,0,Orange); Jerry.range(w,gp_Cols);
  619. A: j+=n; j%=n; S=&subrname[j]; I=S->menur-k; J=S->menuc;
  620. if(I<0) {k+=I; goto D;} if(I>=w) {k+=I-w+1; goto D;}
  621. B: scr(I,J)=sch(16,White+8); Y=y; X=x;
  622. if(c!=-mousemove) Jerry.move(y=I,x=J+1); counterchange(scr(y,x)); c=getkey();
  623. counterchange(scr(y,x)); scr(I,J)=sch(' ',White);
  624. switch(c) {
  625. case -mousemove: x=Jerry.x; y=Jerry.y; if(X==x) if(Y==y) goto A; K=0;
  626.     for(I=0;S=&subrname[I],S[0].name;I++) if(y==S->menur) break; I<?=w-1;
  627.     for(J=I;S=&subrname[J],S[0].name;J++) {
  628.     if(y<S->menur) break; if(S->menuc<=x) j=J;}
  629.     I=subrname[j].menur; J=subrname[j].menuc; goto B;
  630. case -downarrow: j+=10; goto A; case -leftarrow:  j--; goto A;
  631. case -uparrow:   j-=10; goto A; case -rightarrow: j++; goto A;
  632. case -end: case -mbutton: case -rbutton: Jerry=ms; MOAN("user abort");
  633. case CR: case -lbutton: Jerry=ms; return &subrname[j];}}
  634. /*-----*/
  635. Subr*namedsubr(val name){reg int i,j,n=name.n; reg Subr*T; reg char*s,*S=name.s;
  636. if(!n) return subrmenu("subr to call?");
  637. for(i=0;s=(T=&subrname[i])->name;i++) {if(T->n!=n) goto NO;
  638.     for(j=0;j<n;j++) if(s[j]!=S[j]) goto NO; return subrname+i; NO:;} return 0;}
  639. /*-----*/
  640. int keyseqeq(val a,val b){if(a.n==_keyseq) if(b.n==_keyseq)
  641.   if(a.s[0]==b.s[0]) if(byteq(a.s+1,b.s+1,a.s[0]-1)) return 1; return 0;}
  642. /*-----*/
  643. val*getk(val arg,char*prompt/*=0*/){val *f;
  644. if(arg.s) f=&arg.keyseq(); else f=&getkeyseq(prompt); if(f->n==_bad) MOAN(f->s);
  645. if(keyseqc[0]==2) if((byte)keyseqc[1]>=32) MOAN("can't bind a printable char");
  646. return f;}
  647. /*-----*/
  648. char*val::moanifbound(val K,int jump/*=1*/){char*x=0; if(n==_bad) x=s;
  649. else if(K.n==_char ? (K.i<32 ?0: K.i<256) : K.s[0]!=2 ?0: (byte)K.s[1]>=32)
  650.   x="can't bind a printable char";
  651. else if(n?:s!=0) pr(x=CW,"%k is already bound to a %t",&K,n);
  652. if(jump) if(x) MOAN(x); return x;}
  653. /*-----*/
  654. KF(bindkeymacro) {val*f; if(!Macro) MOAN("no macro to bind");
  655. if(Macro->bound.n) {
  656.     pr(CW,"this macro is already bound to %k",&Macro->bound); MOAN(CW);}
  657. f=getk(T1,"type key sequence to bind to current macro");
  658. setrek(T1,keyseq.copy()); f->moanifbound(keyseq);
  659. *f=*Macro; Macro->bound=keyseq.copy();}
  660. /*-----*/
  661. KF(bindkeysubr) {val*f,g;
  662. g=T1.getifn(T1t,"name of subroutine to bind to key:",_subr);
  663. f=getk(T2,"type key sequence to bind to subroutine");
  664. f->moanifbound(keyseq); if(!g.n) MOAN("no such subroutine");
  665. setrek(T1,T1.copy()); setrek(T2,keyseq.copy()); *f=kf(g.S->f);}
  666. /*-----*/
  667. void buffer::bind(val*f,val T1) {if(keyseqeq(T1,bound)) return;
  668. if(bound.n) {pr(CW,"this buffer is already bound to %k",&bound); MOAN(CW);}
  669. f->moanifbound(T1); *f=this; bound=T1.copy(); if(nrows) Sl[lastrow].ok=0;}
  670. /*-----*/
  671. KF(bindkeybuf){
  672. val*f=getk(T1,"type key sequence to bind to current buffer"); B->bind(f,keyseq);
  673. setrek(T1,keyseq.copy());}
  674. /*-----*/
  675. void val::unbind() {switch(n) {
  676. case _keyarray: MOAN("can't unbind a keyarray");
  677. case _buffer: delete b->bound.s; b->bound=val(); break;
  678. case _macro: if(m!=Macro) delete m;
  679.     else {delete m->bound.s; m->bound=val();} break;
  680. case 0: MOAN("this key is already unbound");};
  681. s=0; n=0;}
  682. /*-----*/
  683. KF(unbindkey) {val *f; buffer *BB;
  684. if(T1.s) f=&T1.keyseq(); else f=&getkeyseq("type key sequence to unbind");
  685. if(f->n==_bad) MOAN(f->s); setrek(T1,keyseq.copy()); f->unbind();}
  686. /*----- buffer(char*) : find/get buffer with this filename */
  687. buffer::buffer(char*F,int rd/*=1*/){int i; buffer *BB=B; B=this; initbuffer();
  688. ncols=gp_Cols; linkin();
  689. if(F?F[0]:0) {name=copyof(F); if(rd) read();} else name=copyof("(no file)");
  690. B=BB;}
  691. /*----- returns buffer with this name (0 if no buffer has this name) */
  692. buffer*buf_named(val name){buffer*C;
  693. forallbufs(C) if(C->name) if(!strcmp(C->name,name.s)) return C; return 0;}
  694. /*-----*/
  695. buffer*findbuf(val name){buffer*C;
  696. forallbufs(C) if(!strcmp(C->name,name.s)) return C; return new buffer(name.s);}
  697. /*-----*/
  698. KF(renamebuffer) {
  699. T1.getifn(Fn,"new filename for buffer?",_buffer); setrek(T1,T1.copy());
  700. if(buf_named(T1)) {pr(CW,"%s already has a buffer",Filename); MOAN(CW);}
  701. delete B->name; B->name=new char[strlen(T1.s)+1]; strcpy(B->name,T1.s);
  702. Sl[B->lastrow].ok=0;}
  703. /*-----*/
  704. KF(onewindow) {int i;
  705. for(i=0;i<nwindows;i++) window[i]->row1=window[i]->nrows=window[i]->lastrow=0;
  706. nwindows=1; window[0]=B; B->row1=0; B->nrows=gp_Rows; B->lastrow=gp_Rows-1;
  707. for(i=0;i<gp_Rows;i++) Sl[i].ok=0; currentwindow=0;}
  708. /*-----*/
  709. KF(splitwindow) {
  710. get_file(T1,"file for new window:")->split_window_with(N.n?N.i:B->nrows/2);}
  711. /*-----*/
  712. KF(nextwindow) {int i;
  713. if(N.i<0) for(i=0;i>N.i;i--) {if(--currentwindow<0) currentwindow=nwindows-1;}
  714. else for(i=0;i<N.i;i++) {if(++currentwindow>=nwindows) currentwindow=0;}
  715. B=window[currentwindow]; B->dotcc=B->dotcc2=-1;}
  716. /*-----*/
  717. KF(prevwindow) {nextwindow(-N.i,1);}
  718. /*-----*/
  719. buffer*get_file(val&T1,char*p) {buffer*C=T1.getifn(Fn,p,_buffer).b?:findbuf(T1);
  720. if(!thisstep.T1.n) setrek(T1,T1.copy()); return C;}
  721. /*-----*/
  722. void buffer::operator()(int N/*=0*/){
  723. if(N<0) split_window_with(N==-1?B->nrows/2:-N);
  724. else if(!N) B->dot+=this; else go_to();}
  725. /*-----*/
  726. KF(buffer_){buffer*C=T1.n==_buffer?T1.b:get_file(T1,"go to file:"); (*C)(N.i);
  727. if(T2.n==_keyseq) {
  728.     C->bind(getk(T2,"type key sequence to bind to current buffer"),T2);
  729.     setrek(T2,keyseq.copy());}}
  730. /*-----*/
  731. KF(openfile) {get_file(T1,"go to file:")->go_to();}
  732. /*-----*/
  733. KF(restorebuf) {int i; B->deltext(); B->read();
  734.     for(i=B->row1;i<=B->lastrow;i++) Sl[i].ok=0;}
  735. /*-----*/
  736. buffer*buffer_menu(char*prompt) {mousestate ms; ms=Jerry; Jerry.mc=1;
  737. int c,i,j=0,k,m,n,w=gp_Rows-1,Y=0; val F; char *kk; buffer *D,**C; B->dotcc=-1;
  738. Z: for(n=0,D=bhead;D;D=D->next,n++); C=(buffer**)myalloc(n*sizeof(buffer*));
  739. for(i=0,D=bhead;D;D=D->next,i++) if(B==(C[i]=D)) j=i;
  740. Jerry.range(n,80); Jerry.move(j,0);
  741. E: k=w/2; k=j<w?0:((j-w/4)/k)*k;
  742. for(i=k;i<n;i++) {if(i-k>=w) break;
  743.     pr(CW," %c%2d %s",C[i]->changed?'*':' ',i,C[i]->name);
  744.     if(C[i]->bound.n) pa(CW," (%k)",&C[i]->bound);
  745.     CW[gp_Cols]=0; display(CW,i-k,0,Orange);}
  746. for(i=(w<?n)-1;i>=n-k;i--) display(" ",i,0,Orange);
  747. display("(\030\031 move, esc \032 file not listed, del removes buffer, \
  748. RET chooses)", w<?n,0,Orange);
  749. A: i=k; k=w/2; k=j<w?0:((j-w/4)/k)*k; if(i!=k) goto E;
  750. scr(j-k,0)=sch(2,White); m=j-k; switch(Y=getkey()) {
  751. case -mousemove: j=Jerry.y; break;
  752. case -downarrow: j=(j+1  )%n; break;
  753. case -uparrow:   j=(j-1+n)%n; break;
  754. case -del: if(deletebuffer(C[j])) {j=0; free(C); goto Z;} goto A;
  755. case -rbutton: case -mbutton: case '['-64: scr(j-k,0)=sch(' ',White); F.n=0;
  756.     D=F.getifn(Fn,prompt,_buffer).b?:findbuf(F); goto Q;
  757. case -alt_end: D=B; goto Q;
  758. case CR: case -lbutton: D=C[j]; Q: free(C); Jerry=ms; return D;}
  759. scr(m,0)=sch(' ',White); if(Y!=mousemove) Jerry.move(j,0); goto A;}
  760. /*-----*/
  761. KF(buffermenu) {if(play) MOAN("BUG: obeyed buffermenu from macro");
  762. buffer*C=buffer_menu("file:"); setref(f,&openfile); setrec(N,val(1,0));
  763. setrek(T1,val(C->name).copy()); C->go_to();}
  764. /*----- insert copy of buffer at mark */
  765. void mark::operator+=(buffer*BB){
  766.     if(B==BB) MOAN("can't insert buffer into itself");
  767.     B->dot.yank(Text(BB->text.next,BB->text.prev),1);}
  768. /*-----*/
  769. KF(insertfile) {buffer *C,*Y=B; Text KK; /* don't create new buffer specially */
  770. C=T1.getifn(Fn,"insert file:",_buffer).b?:buf_named(T1.s); setrek(T1,T1.copy());
  771. B=Y; if(B==C) MOAN("can't insert buffer into itself");
  772. if(C) KK=Text(C->text.next,C->text.prev).copy(); else KK.read(T1.s);
  773. region Z=B->dot.yank(KK,0); B->changed=1; if(N.n) B->Mark(N.i)=Z.beg;}
  774. /*-----*/
  775. KF(mergefile) {buffer *C; Text K; line*U,*V,*W,*X,*Y,*Z; int c;
  776. C=T1.getifn(Fn,"merge into region file:",_buffer).b?:buf_named(T1.s);
  777. setrek(T1,T1.copy()); if(B==C) MOAN("can't merge buffer with itself");
  778. if(C) K=Text(C->text.next,C->text.prev).copy(); else K.read(T1.s);
  779. if(!K.end->n) if(K.beg==K.end) return; /* no lines to merge in */
  780.   else {K.end=(X=K.end)->prev; X->del();} /* final empty line */
  781. X=B->dot.r; Z=B->Mark(N.i).r?:X; if(c=Z<X) {W=Z; Z=X; X=W;} K.end->next=0;
  782. U=X=X->prev?:&B->text; Y=K.beg;
  783. L: if(Breakin()) goto END; if(X->next==Z) {*X-*Y; *K.end-*Z; goto END;}
  784. if(compare(X->next,Y)<0) {X=X->next; goto L;}
  785. W=Y; V=X->next; while(W->next?compare(V,W->next)>=0:0) W=W->next;
  786. *X-*Y; Y=W->next; *W-*V; X=V; if(Y) goto L;
  787. END: if(c) B->Mark(N.i)=mark(U->next,0); else B->dot=mark(U->next,0);
  788. B->text.prev->next=B->text.next->prev=0; B->changed=1;}
  789. /*-----*/
  790. KF(readmacros) {
  791. buffer*C=T1.getifn(Fn,"file to read macros from:",_buffer).b?:findbuf(Fn);
  792. val T=T1.copy(),U=T2.copy(); translate(C); setrek(T1,T); setrek(T2,U);}
  793. /*-----*/
  794. KF(accentedletters) {int i; static
  795. char accuc[39]="\200\232\220\203\216\205\217\200\210\211\212\213\214\215\216\
  796. \217\220\222\222\223\231\225\226\227\230\231\23200000\240\241\242\243\245\245";
  797. static
  798. char acclc[39]="\207\201\202\203\204\205\206\207\210\211\212\213\214\215\204\
  799. \206\202\221\221\223\224\225\226\227\230\224\20100000\240\241\242\243\244\244";
  800. for(i=128;i<256;i++) {chtype[i]&=~c_alnum; to__upper[i]=to__lower[i]=i;}
  801. if(N.i) {for(i=0;i<39;i++) if(accuc[i]!='0') {chtype[i]|=c_alnum;
  802.     to__upper[i+128]=accuc[i]; to__lower[i+128]=acclc[i];}}}
  803. /*-----*/
  804. void mark::skipword(int N){int i;
  805. if(N>=0) {for(i=0;i<N;i++) {find_alnum(0,1); skip_alnum(0);}
  806.     if(B->skip_after_word&1) find_alnum(0,1);}
  807. else     {for(i=0;i>N;i--) {find_alnum(1,1); skip_alnum(1);}
  808.     if(B->skip_after_word&2) find_alnum(1,1);}}
  809. /*-----*/
  810. KF(skipwordf){B->dot.skipword(N.i);}
  811. KF(skipwordb){B->dot.skipword(-N.i);}
  812. KF(killwordf){obtype=ob_kill;mark Q=B->dot;Q.skipword( N.i); (B->dot-Q).kill();}
  813. KF(killwordb){obtype=ob_kill;mark Q=B->dot;Q.skipword(-N.i); (Q-B->dot).kill();}
  814. /*-----*/
  815. region thisword(int N/*=1*/){mark L,M=B->dot;
  816. if(N<0)   {if(M.is_alnum()) M.skip_alnum(0); else M.find_alnum(1,1);
  817.     if(!(B->skip_after_word&2)) M.find_alnum(0,1); L=M; L.skipword(N);}
  818. else {L=M; if(L.is_alnum()) L.skip_alnum(1); else L.find_alnum(0,1);
  819.     if(!(B->skip_after_word&1)) L.find_alnum(1,1); M=L; M.skipword(N);}
  820. return L-M;}
  821. /*-----*/
  822. region thispara(){line *K=B->dot.r,*L;
  823. while(!K->is_bop()) K=K->prev;
  824. if(L=K->next) while(!L->is_eop()) if(!(L=L->next)) break;
  825. if(!L) L=(*B->text.prev)/val("",0); return mark(K,0)-mark(L,0);}
  826. /*-----*/
  827. KF(twiddlewords) {region TW=thisword(N.i>=0?1:-1); mark Q=N.i>=0?TW.end:TW.beg;
  828. Q.skipword(N.i); TW.moveto(Q).color(White,Magenta); B->changed=1;}
  829. /*-----*/
  830. KF(twiddlelines) {int i; line *X,*Y,*Z,*U,*V; if(!N.i) return;
  831. Y=B->dot.r; X=Y->prev?:&B->text; Z=Y->next?:&B->text;
  832. if(N.i>0) {U=Y; for(i=0;i<N.i;i++) if(V=U->next) U=V; else break;
  833.     if(Y==U) MOAN("end of buffer");   V=U->next?:&B->text;}
  834. else    {V=Y; for(i=0;i>N.i;i--) if(U=V->prev) V=U; else break;
  835.     if(Y==V) MOAN("start of buffer"); U=V->prev?:&B->text;}
  836. *X-*Z; *U-*Y; *Y-*V; Y->la(1); B->text.prev->next=B->text.next->prev=0;
  837. (mark(Y,0)-mark(Y,Y->n)).color(White,Magenta); B->changed=1;}
  838. /*-----*/
  839. void casechange(int N,line*L,int b,int e){
  840. int i; char t,*s=L->s; byte*cs=N?to__upper:to__lower;
  841. for(i=b;i<e;i++) {t=s[i]; s[i]=cs[(byte)t]; if(t!=s[i]) L->la(1);}}
  842. /*-----*/
  843. void region::Case(int N){line *K,*L; if(beg==end) return; B->changed=1;
  844. for(L=beg.r;L;L=L->next) {if(!L) return;
  845.     casechange(N,L,L==beg.r?beg.c:0,L==end.r?end.c:L->n);
  846.     if(L==end.r) break;}}
  847. /*-----*/
  848. void region::format(){line *K,*L; if(beg==end) return; B->changed=1;
  849. if(beg.c) {end.push(); L=beg/1; end.pop();} else L=beg.r;
  850. if(end.c) {end.push();   end/1; end.pop();}
  851. A: K=L->next; L->de_trailing_space(); L->split_if_long(); if(!K) return;
  852. if(K==end.r) return; L=K->prev; (*L)+=' '; --*L; goto A;}
  853. /*-----*/
  854. KF(formatregion) {(B->Mark(N.i)-B->dot).format();}
  855. KF(upcaseregion) {(B->Mark(N.i)-B->dot).Case(1);}
  856. KF(lwcaseregion) {(B->Mark(N.i)-B->dot).Case(0);}
  857. KF(upcasewords) {region TW=thisword(N.i);
  858.     TW.Case(1); B->dot=N.i<=0?TW.beg:TW.end;}
  859. KF(lwcasewords) {region TW=thisword(N.i);
  860.     TW.Case(0); B->dot=N.i<=0?TW.beg:TW.end;}
  861. KF(capitalize){region TW=thisword(); TW.Case(0); mark Q=TW.end; Q.skip_alnum(1);
  862. if(!Q.eol()) {char*T=&Q.r->s[Q.c]; *T=to_upper(*T); Q.r->la(1);}
  863. B->dot.skipword(1);}
  864. /*-----*//* reformat with left margin */
  865. KF(formatinsetregion) {mark M; char*D=Display; region F=Found; int i,j;
  866. region R(B->Mark(N.i),B->dot); if(R.beg==R.end) return; R.right_order();
  867. T1.getifn(T1t,"chars to prefix to each line:"); setrek(T1,T1.copy());
  868. T2.getifn(T2t,"chars prefixing each line now:",0,T1.s); setrek(T2,T2.copy());
  869. if(T2.n) {char s[T2.n+4]="/{"; val T(s,T2.n+2+0x80000000); s[T2.n+2]=0;
  870.     s[T2.n+3]=0xc0; /*magic*/ Copytext(s+2,T2.s,T2.n); R.replace(T,val("",0));}
  871. i=B->rmargin; B->rmargin=((i>0?i:-i)-T1.n)>?11; R.format(); B->rmargin=i;
  872. if(T1.n) (R.beg-mark(R.end.r->prev,0)).replace(val("/{\000\300",0x80000002),T1);
  873. Found=F; Display=D;}
  874. /*-----*/
  875. val eosentchars(".!?",3);
  876. /*-----*/
  877. void mark::skipsentence(int N){mark Q; int i=0xfff,j,k;
  878. if(N>0) for(k=0;k<N;k++) {A: Q=*this; ++*this; if(!r) {*this=Q; return;}
  879.     j=i; i=**this; if(eosentchars>>j) if(iswhite(i)) continue; goto A;}
  880. else    for(k=0;k>N;k--) {C: Q=*this; --*this; if(!r) {*this=Q; return;}
  881.     j=i; i=**this; if(eosentchars>>i) if(iswhite(j)) continue; goto C;}}
  882. /*-----*/
  883. KF(killsent) {
  884. obtype=ob_kill; mark Q=B->dot; Q.skipsentence(N.i); (B->dot-Q).kill();}
  885. /*-----*/
  886. int line::is_bop(){if(n) if(iswhite(s[0])) return 1;
  887. if(!prev) return 1; return prev->blank();}
  888. /*-----*/
  889. int line::is_eop(){if(!n) return 1; return iswhite(s[0]);}
  890. /*-----*/
  891. void mark::skippara(int N){line *K,*L; int i,j;
  892. if(N>0){for(i=0;i<N;i++) {for(L=r;K=L->next;L=K){if(L!=r)if(K->is_eop()) break;}
  893.     if(!K) K=*L/val("",0); r=K; c=0;}}
  894. else   {for(i=0;i>N;i--) {for(L=r;K=L->prev;L=K) if(L!=r) if(K->is_bop()) break;
  895.     r=K?:L; c=0;}}}
  896. /*-----*/
  897. KF(skipsentf) {B->dot.skipsentence(N.i);}
  898. KF(skipsentb) {B->dot.skipsentence(-N.i);}
  899. KF(skipparaf) {B->dot.skippara(N.i);}
  900. KF(skipparab) {B->dot.skippara(-N.i);}
  901. KF(formatpara) {thispara().format();}
  902. /*-----*/
  903. KF(callsubr) {val f=T1.getifn(T1t,"subr name:",_subr);
  904. if(!f.n) MOAN("no such subroutine or macro");
  905. if(f.n==_macro) {(*f.m)(N); setrec(f,f.m);}
  906. else {f.S->f(N,val(),val()); setref(f,f.S->f);}}
  907. /*-----*/
  908. KF(gotoline) {int i; gotobof(); for(i=1;i<N.i;i++) godown();}
  909. /*-----*/
  910. KF(prkeys) {keys.print(N.i);}
  911. /*-----*/
  912. KF(prkeynames) {int i; char *s;
  913. for(i=0;i<256;i++) if(s=altnames[i]) {*B+=s; newline();}
  914. for(i=0;i<255;i++) if(s=keyname(i,0), strlen(s)>1) {*B+=s; newline();}
  915. *B+="(the other printable characters represent themselves)\n";}
  916. /*-----*/
  917. KF(prsubrnames) {int i; char *s;
  918. for(i=0;s=subrname[i].name;i++) {*B+=s; newline();}}
  919. /*-----*/
  920. KF(gotonbuf) {buffer*A;
  921. if(!N.n) {A=B; do{A=A->next?:bhead;} while(A->nrows?A!=B:0); A->go_to();}
  922. else {int i; A=bhead; for(i=0;i<N.i;i++) if(!(A=A->next)) break;
  923.    if(A) A->go_to();
  924.    else {pr(CW,"there are < %1d buffers",N.i); MOAN(CW);}}}
  925. /*-----*/
  926. KF(copytext){(B->Mark(N.i)-B->Mark(N.i+1)).copyto(B->dot).color(White,Magenta);}
  927. /*-----*/
  928. KF(movetext){(B->Mark(N.i)-B->Mark(N.i+1)).moveto(B->dot).color(White,Magenta);}
  929. /*-----*/
  930. KF(delblanklines) {line*K,*L,*Z; K=L=Z=B->dot.r; if(!K->blank()) return;
  931. while(L=K->prev,L?L->blank():0) K=L; while(Z->next?Z->blank():0) Z=Z->next;
  932. (mark(K,0)-mark(Z,0)).Delete(0); B->changed=1;}
  933. /*-----*/
  934. KF(deletewhite) {int i,j,k; line*L=B->dot.r; j=k=B->dot.c;
  935. while(!j     ?0:((i=L->s[j-1]),i==' '?1:i==9)) j--;
  936. while(k>=L->n?0:((i=L->s[k  ]),i==' '?1:i==9)) k++;
  937. (mark(L,j)-mark(L,k)).Delete(0); B->dot.r->la(1); B->changed=1;}
  938. /*-----*/
  939. KF(leaveonewhite) {deletewhite(N,T1,T2); B->dot+=' ';}
  940. /*-----*/
  941. KF(calldos) {T1.getifn(T1t,"DOS command:"); setrek(T1,T1.copy()); clearscreen();
  942. int i=system(T1.s); getkey(); if(i) Moan="DOS command error";}
  943. /*-----*/
  944. int compare(line*X,line*Y){reg int i; reg char *x=X->s,*y=Y->s;
  945. i=B->sortcol; if(i>=X->n) return i>=Y->n?0:-1; else if(i>=Y->n) return 1;
  946. x+=i; y+=i; reg char *z=x+(X->n<?Y->n);
  947. if(B->Case) {
  948.     for(;i=(byte)*x-(byte)*y,x<z;x++,y++) if(i) return i; return X->n-Y->n;}
  949. else {
  950.     for(;i=(byte)to__lower[(byte)*x]-(byte)to__lower[(byte)*y],x<z;x++,y++)
  951.       if(i) return i; return X->n-Y->n;}}
  952. /*-----*/
  953. KF(sortlines){int i,j,k; mark x=B->dot,y=B->Mark(N.i),z,*M;
  954. if(y<x) {z=x; x=y; y=z;} line*a=x.r,*b=y.r,*X,*Y,*e; if(a==b?:a->next==b)return;
  955. B->changed=1; z=B->dot; for(j=1,e=a;e?e!=b:0;e=e->next) j++;
  956. for(k=0,i=1;Breakin()?0:i?k<=j:0;k++) {reg short n; reg char*s;
  957.     if(a==b?:a->next==b) goto Z; e=a; i=0;
  958.     for(Y=(X=a)->next;Y!=b;X=Y,Y=Y->next) if(compare(X,Y)>0) {
  959.     e=Y; i=1; X->la(1); Y->la(1);
  960.     n=X->n; X->n=Y->n; Y->n=n; s=X->s; X->s=Y->s; Y->s=s;}
  961.     B->dot=mark(e,0); B->start.c<?=B->start.r->n;
  962.     forallmarks(M) M->c<?=M->r->n; B->display();
  963.     for(X=(Y=b->prev)->prev;;Y=X,X=X->prev) {if(compare(X,Y)>0) {
  964.     e=Y; i=1; X->la(1); Y->la(1);
  965.     n=X->n; X->n=Y->n; Y->n=n; s=X->s; X->s=Y->s; Y->s=s;} if(X==a) break;}
  966.     B->dot=mark(e,0); B->start.c<?=B->start.r->n; b=b->prev; if(a!=b) a=a->next;
  967.     Z: forallmarks(M) M->c<?=M->r->n; B->display();}
  968. z.c<?=z.r->n; B->dot=z;}
  969. /*-----*/
  970. KF(setsortcol) {if(N.n) B->sortcol=N.i>?0;
  971. pr(disp,"sortlines will ignore the first %1d chars in lines",B->sortcol);
  972. Display=disp;}
  973. /*-----*/
  974. KF(expandtabs) {(B->dot-B->Mark(N.i)).expandtabs();}
  975. /*-----*/
  976. KF(maketabs) {(B->dot-B->Mark(N.i)).maketabs();}
  977. /*-----*/
  978. KF(displayhex) {mark M=B->dot; int i=0,j; static char d[17]="0123456789abcdef";
  979. char*e=CW+512;
  980. A: if(M.c>=M.r->n) {if(!M.r->next) goto Z;
  981.     if(!M.r->no_cr()) {e[i]=CR; CW[i++]='0'; e[i]=' '; CW[i++]=d[CR];}
  982.     e[i]=LF; CW[i++]='0'; e[i]=' '; CW[i++]=d[LF];
  983.     M.r=M.r->next; M.c=0; goto A;}
  984. j=M.r->s[M.c++]; e[i]=j?:' '; CW[i++]=d[(j>>4)&15]; e[i]=' '; CW[i++]=d[j&15];
  985. if(i<256) goto A;
  986. Z: e[i]=0; CW[i]=0; Moan=e; Display=CW;}
  987. /*-----*/
  988. KF(version) {Display=VERSION;}
  989. /*-----*/
  990. KF(dis_play) {T1.getifn(T1t,"text to display?"); setrek(T1,T1.copy());
  991. display(T1.s,B->lastrow,0,Cyan);}
  992.